﻿using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using GKS.WtcrMvc.Models;

namespace GKS.WtcrMvc.MVVC {
    /// <summary>
    /// The MVVC of the contacts (people or companies)
    /// </summary>
    public class ContactMVVC {
        #region instance variables
        /// <summary>
        /// The contact of this contact mvvc
        /// </summary>
        private Contact contact;

        /// <summary>
        /// The person of this contact mvvc
        /// </summary>
        private Person person;

        /// <summary>
        /// The company of this contact mvvc
        /// </summary>
        private Company company;
        #endregion

        #region properties
        [Description("The ID of this contact.")]
        [ReadOnly(isReadOnly: true)]
        public Guid Id { get; set; }

        [DisplayName("Is Person")]
        [ReadOnly(isReadOnly: true)]
        public bool IsPerson { get; private set; }

        [DisplayName("Is Company")]
        [ReadOnly(isReadOnly: true)]
        public bool IsCompany { get; private set; }

        [DisplayName("Contact")]
        public Contact Contact {
            get {
                return contact;
            }
            set {
                contact = value;

                if (contact != null) {
                    this.ContactId = contact.Id;
                    this.ContactCompanies = contact.Companies;
                    this.ContactCompanyContacts = contact.CompanyContacts;
                    this.ContactCreatedIn = contact.CreatedIn;
                    this.ContactFullName = contact.FullName;
                    this.ContactLastUpdate = contact.LastUpdate;
                    this.ContactNotes = contact.ContactNotes;
                    this.ContactPeople = contact.People;
                }
            }
        }

        [DisplayName("Person")]
        public Person Person {
            get {
                return person;
            }
            set {
                person = value;

                if (person != null) {
                    this.Contact = person.Contact;
                    this.IsPerson = true;
                    this.PersonAddresses = person.PersonAddresses;
                    this.PersonCompany = person.Company;
                    this.PersonCompanyId = person.CompanyId;
                    this.PersonConsultants = person.Consultants;
                    this.PersonContact = person.Contact;
                    this.PersonContactId = person.ContactId;
                    this.PersonCreatedIn = person.CreatedIn;
                    this.PersonEmployees = person.Employees;
                    this.PersonFirstName = person.FirstName;
                    this.PersonId = person.Id;
                    this.PersonIsSystemUser = person.IsSystemUser;
                    this.PersonLastName = person.LastName;
                    this.PersonLastUpdate = person.LastUpdate;
                    this.PersonMiddleName = person.MiddleName;
                    this.PersonNotes = person.PersonNotes;
                    this.PersonTitle = person.Title;
                    this.PersonUser = person.User;
                    this.PersonUserId = person.UserId;
                }
            }
        }

        public Company Company {
            get {
                return company;
            }
            set {
                company = value;

                if (company != null) {
                    this.Contact = company.Contact;
                    this.IsCompany = true;
                    this.CompanyAddresses = company.CompanyAddresses;
                    this.CompanyContact = company.Contact;
                    this.CompanyContactId = company.ContactId;
                    this.CompanyContacts = company.CompanyContacts;
                    this.CompanyCreatedIn = company.CreatedIn;
                    this.CompanyCustomers = company.Customers;
                    this.CompanyId = company.Id;
                    this.CompanyLastUpdate = company.LastUpdate;
                    this.CompanyNotes = company.CompanyNotes;
                    this.CompanyPeople = company.People;
                    this.CompanySuppliers = company.Suppliers;
                    this.CompanyVAT = company.VAT;
                }
            }
        }

        #region contact properties
        [Description("The ID of the contact contained in this contact mvvc.")]
        [DisplayName("Contact ID")]
        [ReadOnly(isReadOnly: true)]
        public System.Guid ContactId { get; set; }

        [DisplayName("Full Name")]
        [Description("The full name of the contact contained in this contact mvvc.")]
        [StringLength(100)]
        [Required]
        public string ContactFullName { get; set; }
        
        [DisplayName("Contact's creation date")]
        [DataType(DataType.DateTime)]
        [ReadOnly(isReadOnly: true)]
        public System.DateTime ContactCreatedIn { get; set; }
        
        [DisplayName("Contact's last update")]
        [DataType(DataType.DateTime)]
        [ReadOnly(isReadOnly: true)]
        public System.DateTime ContactLastUpdate { get; set; }
        #endregion

        #region person properties
        [DisplayName("Person ID")]
        [Description("The ID of the Person model instance that contains the Person data.")]
        public Guid PersonId { get; set; }
        
        [DisplayName("Referred contact ID")]
        [Description("The ID of the contact record this person record referrs to.")]
        public Guid PersonContactId { get; set; }
        
        [DisplayName("Employing company ID")]
        public Nullable<Guid> PersonCompanyId { get; set; }
        
        [DisplayName("Title")]
        [StringLength(10)]
        [Description("The title of this person (Mr., Mrs., Miss, etc).")]
        public string PersonTitle { get; set; }
        
        [DisplayName("First Name")]
        [StringLength(32)]
        [Description("The first name of this person.")]
        public string PersonFirstName { get; set; }
        
        [DisplayName("Middle Name")]
        [StringLength(32)]
        [Description("The middle name of this person.")]
        public string PersonMiddleName { get; set; }
        
        [DisplayName("Last Name")]
        [StringLength(32)]
        [Description("The last name of this person.")]
        public string PersonLastName { get; set; }
        
        [DisplayName("Is system user")]
        [Required]
        [DefaultValue(false)]
        [Description("A flag that indicates if the person is also a system user")]
        public bool PersonIsSystemUser { get; set; }
        
        [DisplayName("User ID")]
        [Description("The ID of the system user assigned to this person.")]
        public Nullable<Guid> PersonUserId { get; set; }
        
        [DisplayName("Person's creation date")]
        [DataType(DataType.DateTime)]
        [ReadOnly(isReadOnly: true)]
        [Description("The moment in time when this Person record was created in the system.")]
        public DateTime PersonCreatedIn { get; set; }
        
        [DisplayName("Person's last update")]
        [DataType(DataType.DateTime)]
        [ReadOnly(isReadOnly: true)]
        [Description("The last moment in time when this record was updated in the system.")]
        public DateTime PersonLastUpdate { get; set; }
        #endregion

        #region company properties
        [DisplayName("Company ID")]
        [Description("The company model instance ID.")]
        public Guid CompanyId { get; set; }

        [DisplayName("Company's reference contact")]
        [Description("The ID of the reference contact for this company model instance")]
        public Guid CompanyContactId { get; set; }

        [DisplayName("VAT Code")]
        [StringLength(32)]
        public string CompanyVAT { get; set; }

        [DisplayName("Company's creation date")]
        [DataType(DataType.DateTime)]
        [Description("The moment in time when the Company record was created in the system")]
        public DateTime CompanyCreatedIn { get; set; }

        [DisplayName("Company's last update")]
        [DataType(DataType.DateTime)]
        [Description("The last moment in time when the company record was updated in the system.")]
        public DateTime CompanyLastUpdate { get; set; }
        #endregion
        #endregion

        #region constructors
        /// <summary>
        /// The constructor of an empty ContactMVVC instance.
        /// </summary>
        public ContactMVVC() {
            this.Id = Guid.NewGuid();
        }

        /// <summary>
        /// The constructor of a ContactMVVC instance.
        /// </summary>
        /// <param name="contact">The Contact model instance which contains the initial data.</param>
        public ContactMVVC(Contact contact) : this() {
            this.Contact = contact;
        }

        /// <summary>
        /// The constructor of a ContactMVVC instance.
        /// </summary>
        /// <param name="person">The Person model instance which contains the initial data.</param>
        public ContactMVVC(Person person) : this() {
            this.Person = person;
        }

        /// <summary>
        /// The constructor of a ContactMVVC instance.
        /// </summary>
        /// <param name="company">The Company model instance which contains the initial data.</param>
        public ContactMVVC(Company company) : this() {
            this.Company = company;
        }

        /// <summary>
        /// The constructor of a ContactMVVC instance.
        /// </summary>
        /// <param name="person">The Person model instance which contains part of the initial data.</param>
        /// <param name="company">The Company model instance which contains part of the initial data.</param>
        public ContactMVVC(Person person, Company company) : this(person) {
            this.Company = company;
        }
        #endregion

        #region relations
        #region contact relations
        [DisplayName("Companies")]
        public virtual ICollection<Company> ContactCompanies { get; set; }

        [DisplayName("Contact's Company contacts")]
        public virtual ICollection<CompanyContact> ContactCompanyContacts { get; set; }

        [DisplayName("Contact's Notes")]
        public virtual ICollection<ContactNote> ContactNotes { get; set; }

        [DisplayName("Contact's related people")]
        public virtual ICollection<Person> ContactPeople { get; set; }
        #endregion

        #region person relations
        [DisplayName("Employing company")]
        public virtual Company PersonCompany { get; set; }

        [DisplayName("Consultants")]
        public virtual ICollection<Consultant> PersonConsultants { get; set; }
        
        [DisplayName("Referred contact")]
        public virtual Contact PersonContact { get; set; }

        [DisplayName("Employees")]
        public virtual ICollection<Employee> PersonEmployees { get; set; }

        [DisplayName("User")]
        public virtual User PersonUser { get; set; }

        [DisplayName("Addresses")]
        public virtual ICollection<PersonAddress> PersonAddresses { get; set; }

        [DisplayName("Notes")]
        public virtual ICollection<PersonNote> PersonNotes { get; set; }
        #endregion

        #region company relations
        [DisplayName("Company's reference contact")]
        public virtual Contact CompanyContact { get; set; }

        [DisplayName("Company's addresses")]
        public virtual ICollection<CompanyAddress> CompanyAddresses { get; set; }

        [DisplayName("Company's contacts")]
        public virtual ICollection<CompanyContact> CompanyContacts { get; set; }

        [DisplayName("Notes regarding the company")]
        public virtual ICollection<CompanyNote> CompanyNotes { get; set; }

        [DisplayName("Customer companies")]
        public virtual ICollection<Customer> CompanyCustomers { get; set; }

        [DisplayName("Company's related people")]
        public virtual ICollection<Person> CompanyPeople { get; set; }

        [DisplayName("Supplier companies")]
        public virtual ICollection<Supplier> CompanySuppliers { get; set; }
        #endregion
        #endregion

        #region methods
        #region instance methods

        #endregion

        #region static/utility methods
        /// <summary>
        /// A method that imports the data from a collection of contacts.
        /// </summary>
        /// <param name="contacts">The collection of contacts that should be converted.</param>
        /// <returns></returns>
        public static IEnumerable<ContactMVVC> ConvertContactData(IEnumerable<Contact> contacts) {
            List<ContactMVVC> mvvcList = new List<ContactMVVC>();

            foreach (var c in contacts) {
                mvvcList.Add(new ContactMVVC(c));
            }

            return mvvcList;
        }
        #endregion
        #endregion

        #region custom operators
        /// <summary>
        /// An explicit conversion operator from Contact to ContactMVVC
        /// </summary>
        /// <param name="contact">The contact to be converted</param>
        /// <returns>The corresponding ContactMVVC</returns>
        public static explicit operator ContactMVVC(Contact contact) {
            return new ContactMVVC(contact);
        }

        /// <summary>
        /// An explicit conversion operator from Person to ContactMVVC
        /// </summary>
        /// <param name="contact">The person to be converted</param>
        /// <returns>The corresponding ContactMVVC</returns>
        public static explicit operator ContactMVVC(Person person) {
            return new ContactMVVC(person);
        }

        /// <summary>
        /// An explicit conversion operator from Company to ContactMVVC
        /// </summary>
        /// <param name="contact">The company to be converted</param>
        /// <returns>The corresponding ContactMVVC</returns>
        public static explicit operator ContactMVVC(Company company) {
            return new ContactMVVC(company);
        }
        #endregion
    }
}